#include <stdio.h>

static void cputch(int c, int *cnt) {
    cons_putc(c);
    (*cnt)++;
}

void putchar(int c) { cons_putc(c); }

int puts(const char *str) {
    int cnt = 0;
    char c;
    while((c = *str++) != '\0') {
        cputch(c, &cnt);
    }
    putchar('\n');
    return cnt + 1;
}

/* print fmt tto string with size */
/* 
   %p 转换为 unsigned long 类型, 添加 "0x" 前缀
   %l   %ld   %lu
   %x 十六进制形式输出无符号整数
*/
int vsnprintf(char *str, size_t size, const char *format, va_list ap) {
    int count = 0;
    while (*format && count < size - 1) {
        if (*format == '%') {
            format++;
            switch (*format) {
                case 'd': {
                    int num = va_arg(ap, int);
                    char buf[20];
                    int i = 0;
                    if (num < 0) {
                        if (count < size - 1) {
                            str[count++] = '-';
                        }
                        num = -num;
                    }
                    if (num == 0) {
                        if (count < size - 1) {
                            str[count++] = '0';
                        }
                    } else {
                        while (num > 0) {
                            buf[i++] = num % 10 + '0';
                            num /= 10;
                        }
                        for (int j = i - 1; j >= 0 && count < size - 1; j--) {
                            str[count++] = buf[j];
                        }
                    }
                    break;
                }
                case 's': {
                    const char *s = va_arg(ap, const char *);
                    while (*s && count < size - 1) {
                        str[count++] = *s++;
                    }
                    break;
                }
                case 'p': {
                    void *ptr = va_arg(ap, void *);
                    unsigned long num = (unsigned long)ptr;
                    char buf[20];
                    int i = 0;
                    if (num == 0) {
                        if (count < size - 1) {
                            str[count++] = '0';
                        }
                    } else {
                        while (num > 0) {
                            int digit = num % 16;
                            if (digit < 10) {
                                buf[i++] = digit + '0';
                            } else {
                                buf[i++] = digit - 10 + 'a';
                            }
                            num /= 16;
                        }
                        if (count < size - 1) {
                            str[count++] = '0';
                        }
                        if (count < size - 1) {
                            str[count++] = 'x';
                        }
                        for (int j = i - 1; j >= 0 && count < size - 1; j--) {
                            str[count++] = buf[j];
                        }
                    }
                    break;
                }
                case 'l': {
                    format++;
                    if (*format == 'd') {
                        long num = va_arg(ap, long);
                        char buf[20];
                        int i = 0;
                        if (num < 0) {
                            if (count < size - 1) {
                                str[count++] = '-';
                            }
                            num = -num;
                        }
                        if (num == 0) {
                            if (count < size - 1) {
                                str[count++] = '0';
                            }
                        } else {
                            while (num > 0) {
                                buf[i++] = num % 10 + '0';
                                num /= 10;
                            }
                            for (int j = i - 1; j >= 0 && count < size - 1; j--) {
                                str[count++] = buf[j];
                            }
                        }
                    } else if (*format == 'u') {
                        unsigned long num = va_arg(ap, unsigned long);
                        char buf[20];
                        int i = 0;
                        if (num == 0) {
                            if (count < size - 1) {
                                str[count++] = '0';
                            }
                        } else {
                            while (num > 0) {
                                buf[i++] = num % 10 + '0';
                                num /= 10;
                            }
                            for (int j = i - 1; j >= 0 && count < size - 1; j--) {
                                str[count++] = buf[j];
                            }
                        }
                    }
                    break;
                }
                case 'x': {
                    unsigned int num = va_arg(ap, unsigned int);
                    char buf[20];
                    int i = 0;
                    if (num == 0) {
                        if (count < size - 1) {
                            str[count++] = '0';
                        }
                    } else {
                        while (num > 0) {
                            int digit = num % 16;
                            if (digit < 10) {
                                buf[i++] = digit + '0';
                            } else {
                                buf[i++] = digit - 10 + 'a';
                            }
                            num /= 16;
                        }
                        for (int j = i - 1; j >= 0 && count < size - 1; j--) {
                            str[count++] = buf[j];
                        }
                    }
                    break;
                }
                default:
                    if (count < size - 1) {
                        str[count++] = *format;
                    }
                    break;
            }
        } else {
            if (count < size - 1) {
                str[count++] = *format;
            }
        }
        format++;
    }
    if (count < size) {
        str[count] = '\0';
    }
    return count;
}

int vsprintf(char *str, const char *format, va_list ap) {
    return vsnprintf(str, SIZE_MAX, format, ap);
}

int sprintf(char *str, const char *format, ...) {
    va_list ap;
    va_start(ap, format);
    int result = vsprintf(str, format, ap);
    va_end(ap);
    return result;
}

int snprintf(char *str, size_t size, const char *format, ...) {
    va_list ap;
    va_start(ap, format);
    int result = vsnprintf(str, size, format, ap);
    va_end(ap);
    return result;
}

int printf(const char *format, ...) {
    va_list ap;
    va_start(ap, format);
    char buffer[BUF_SIZE];
    int result = vsnprintf(buffer, BUF_SIZE, format, ap);
    for (int i = 0; i < result; i++) {
        putchar(buffer[i]);
    }
    va_end(ap);
    return result;
}